package com.loe.ktui

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.TypedArray
import android.graphics.*
import android.graphics.drawable.Drawable
import android.text.InputFilter
import android.text.InputType
import android.text.TextUtils.TruncateAt
import android.text.method.DigitsKeyListener
import android.util.AttributeSet
import android.util.TypedValue
import android.view.MotionEvent
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import androidx.core.content.res.getBooleanOrThrow
import androidx.core.content.res.getDimensionOrThrow
import androidx.core.content.res.getIntOrThrow
import androidx.core.content.res.getStringOrThrow
import androidx.core.view.isVisible
import androidx.core.widget.addTextChangedListener
import com.loe.ktui.util.KtColor
import com.loe.ktui.util.KtCornerProvider
import com.loe.ktui.util.KtDecimalInputFilter
import java.util.*

open class UiEdit(id: String? = null) : UiView(id)
{
    companion object
    {
        const val INPUT_TEXT = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
        const val INPUT_TEXT_CODE = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
        const val INPUT_DECIMAL = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
        const val INPUT_NUMBER = InputType.TYPE_CLASS_NUMBER
        const val INPUT_PASSWORD = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
    }

    var text: CharSequence? = null
    var textColor: Int? = null
    var autoText: CharSequence? = null
    var hint: String? = null
    var hintColor: Int? = null
    var gravity: Int? = null
    var isTextSelectable: Boolean? = null
    var minLines: Int? = null
    var maxLines: Int? = null
    var ellipsis: TruncateAt? = null
    var bold: Boolean? = null
    var italic: Boolean? = null
    var textStyle: String? = null
    var textSize: Any? = null
    var isAutoVisible: Boolean? = null
    var isClear: Boolean? = null
    var clearColor: Int? = null
    var clearSize: Any? = null
    var inputType: Int? = null
    var limitNumber: Int? = null
    var limitDecimal: Int? = null
    var maxLen: Int? = null
    var filter: String? = null
    var imeOptions: Int? = null

    var onText: (KtEditText.(s: String) -> Unit)? = null
    fun onText(onText: KtEditText.(s: String) -> Unit)
    {
        this.onText = onText
    }

    open fun initUI(context: Context, view: KtEditText)
    {
        super.initUI(context, view)

        isAlphaClick?.let { view.isAlphaClick = it }

        isAutoVisible?.let { view.isAutoVisible = it }
        text?.let { view.setText(it)}
        view.setTextColor(textColor ?: KtColor.text)
        autoText?.let { view.autoText = it }
        hint?.let { view.hint = it }
        hintColor?.let { view.setHintTextColor(it) }
        gravity?.let { view.gravity = it }
        isTextSelectable?.let { view.setTextIsSelectable(it) }
        minLines?.let { view.minLines = it }
        maxLines?.let {
            view.maxLines = it
            view.isSingleLine = it == 1
        }
        ellipsis?.let { view.ellipsize = it }
        bold?.let { view.setBold(it) }
        italic?.let { view.setItalic(it) }
        textStyle?.let { view.setTextStyle(it) }
        textSize?.let { view.setTextSize(TypedValue.COMPLEX_UNIT_PX, it.distFloat) }
        isClear?.let { view.initClear(it, (clearSize ?: (textSize ?: 14)).dist, clearColor) }
        inputType?.let { view.inputType = it }

        limitNumber?.let { view.limitNumber = it }
        limitDecimal?.let { view.limitDecimal = it }
        maxLen?.let { view.maxLenFilter = InputFilter.LengthFilter(it) }
        if (limitNumber != null || limitDecimal != null || maxLen != null) view.resetLimit()

        filter?.let { view.setFilter(it) }
        imeOptions?.let { view.imeOptions = it }

        onText?.let { onText -> view.setTextListener { view.onText(it) } }
    }

    /** 创建view */
    override fun createView(context: Context, parent: ViewGroup?): KtEditText
    {
        return KtEditText(context).also()
        {
            initUI(context, it)
            addToParent(parent, it)
        }
    }
}

fun Any.ui_Edit(id: String? = null, block: (UiEdit.() -> Unit)? = null): UiEdit
{
    val ui = UiEdit(id)
    block?.let { ui.it() }
    if (this is UiGroup) addChild(ui)
    return ui
}

@SuppressLint("AppCompatCustomView")
open class KtEditText : EditText
{
    constructor(context: Context) : super(context)
    {
        initXML()
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    {
        initXML(context.obtainStyledAttributes(attrs, R.styleable.KtEditText))
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    {
        initXML(context.obtainStyledAttributes(attrs, R.styleable.KtEditText, defStyleAttr, 0))
    }

    private fun initXML(typedArray: TypedArray? = null)
    {
        typedArray?.let()
        {
            if (it.hasValue(R.styleable.KtEditText_kt_corner))
            {
                val corner = it.getDimensionOrThrow(R.styleable.KtEditText_kt_corner).toInt()
                val cornerDirect = KtDirects[it.getInt(R.styleable.KtEditText_kt_cornerDirect, 4)]

                outlineProvider = KtCornerProvider(corner, cornerDirect, this)
            }
            if (it.hasValue(R.styleable.KtEditText_kt_isAlphaClick))
            {
                isAlphaClick = it.getBooleanOrThrow(R.styleable.KtEditText_kt_isAlphaClick)
            }

            if (it.hasValue(R.styleable.KtEditText_kt_isAutoVisible))
            {
                isAutoVisible = it.getBooleanOrThrow(R.styleable.KtEditText_kt_isAutoVisible)
            }
            if (it.hasValue(R.styleable.KtEditText_kt_autoText))
            {
                isAutoVisible = true
                autoText = it.getStringOrThrow(R.styleable.KtEditText_kt_autoText)
            }

            var isReset = false
            if (it.hasValue(R.styleable.KtEditText_kt_limitNumber))
            {
                isReset = true
                limitNumber = it.getIntOrThrow(R.styleable.KtEditText_kt_limitNumber)
            }
            if (it.hasValue(R.styleable.KtEditText_kt_limitDecimal))
            {
                isReset = true
                limitDecimal = it.getIntOrThrow(R.styleable.KtEditText_kt_limitDecimal)
            }
            if (it.hasValue(R.styleable.KtEditText_kt_maxLen))
            {
                isReset = true
                val max = it.getIntOrThrow(R.styleable.KtEditText_kt_maxLen)
                maxLenFilter = InputFilter.LengthFilter(max)
            }
            if (isReset) resetLimit()

            if (it.hasValue(R.styleable.KtEditText_kt_filter))
            {
                val filter = it.getStringOrThrow(R.styleable.KtEditText_kt_filter)
                setFilter(filter)
            }
            if (it.hasValue(R.styleable.KtEditText_kt_isClear))
            {
                val isClear = it.getBooleanOrThrow(R.styleable.KtEditText_kt_isClear)
                val clearSize = it.getDimensionPixelOffset(R.styleable.KtEditText_kt_clearSize, textSize.toInt())
                var clearColor: Int? = it.getColor(R.styleable.KtEditText_kt_clearColor, 0)
                if (clearColor == 0) clearColor = null
                initClear(isClear, clearSize, clearColor)
            }

            it.recycle()
        }
    }

    /******************************************* 清除 *******************************************/

    var isClear = false

    internal fun initClear(isClear: Boolean, clearSize: Int, clearColor: Int? = null)
    {
        this.isClear = isClear
        if (!isClear) return

        var clearDrawable = compoundDrawables[2]
        if (clearDrawable == null)
        {
            clearDrawable = resources.getDrawable(R.mipmap.kt_icon_clear_gray_min, context.theme)
        }
        clearDrawable.setBounds(0, 0, clearSize, clearSize)
        if (clearColor != null) clearDrawable.colorFilter = PorterDuffColorFilter(clearColor, PorterDuff.Mode.SRC_ATOP)

        fun setClearIconVisible(visible: Boolean)
        {
            val right: Drawable? = if (visible) clearDrawable else null
            setCompoundDrawables(compoundDrawables[0], compoundDrawables[1], right, compoundDrawables[3])
            compoundDrawablePadding = ktPx(8.0)
        }

        // 默认设置隐藏图标
        setClearIconVisible(false)
        // 设置焦点改变的监听
        var hasFocus = false
        // 设置输入框里面内容发生改变的监听
        setOnFocusChangeListener()
        { v, hFocus ->
            hasFocus = hFocus
            onClearFocusListener?.invoke(hasFocus)
            if(this.isClear) setClearIconVisible(hasFocus && text.isNotEmpty())
        }
        addKtTextAfterListener()
        {
            if (hasFocus && this.isClear)
            {
                setClearIconVisible(text.isNotEmpty())
            }
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean
    {
        if (isClear && event.action == MotionEvent.ACTION_UP)
        {
            if (compoundDrawables[2] != null)
            {
                val touchable = event.x > width - totalPaddingRight &&
                    event.x < width - paddingRight
                if (touchable)
                {
                    setText("")
                }
            }
        }
        return super.onTouchEvent(event)
    }

    /******************************************* 处理 *******************************************/

    internal var maxLenFilter: InputFilter? = null
    internal var limitNumber: Int = -1
    internal var limitDecimal: Int = -1

    fun setLimitNumber(limitNumber: Int)
    {
        this.limitNumber = limitNumber
        resetLimit()
    }

    fun setLimitDecimal(limitDecimal: Int)
    {
        this.limitDecimal = limitDecimal
        resetLimit()
    }

    fun setMaxLen(max: Int)
    {
        maxLenFilter = InputFilter.LengthFilter(max)
        resetLimit()
    }

    internal fun resetLimit()
    {
        val filters = ArrayList<InputFilter>()
        if (maxLenFilter != null)
        {
            filters.add(maxLenFilter!!)
        }
        if (limitNumber > 0 || limitDecimal > 0)
        {
            val ln = if(limitNumber < 0) 16 else limitNumber
            val ld = if(limitDecimal < 0) 2 else limitDecimal
            filters.add(KtDecimalInputFilter(ln, ld))
        }
        if (filters.isNotEmpty()) setFilters(filters.toTypedArray())
    }

    fun setFilter(s: String)
    {
        keyListener = DigitsKeyListener.getInstance(s)
    }

    /******************************************* 其他 *******************************************/

    var isAutoVisible: Boolean = false

    var autoText: CharSequence?
        get() = text
        set(value)
        {
            if (isAutoVisible) isVisible = value != null && value.trim().isNotEmpty()
            setText(value)
        }

    var isAlphaClick = false
        set(value)
        {
            field = value
            isClickable = value
        }

    override fun dispatchSetPressed(pressed: Boolean)
    {
        if (isAlphaClick) alpha = if (pressed || !isEnabled) 0.75f else 1f
        super.dispatchSetPressed(pressed)
    }

    override fun setEnabled(enabled: Boolean)
    {
        if (isAlphaClick) alpha = if (enabled) 1f else 0.75f
        super.setEnabled(enabled)
    }

    private var onText: ((s: String) -> Unit)? = null

    private val addTextChanged by lazy {
        addKtTextAfterListener()
        {
            onText?.invoke(it)
        }
    }

    fun setTextOutOnText(value: CharSequence)
    {
        val on = this.onText
        this.onText = null
        setText(value)
        this.onText = on
    }

    fun setTextListener(initText: CharSequence? = null, onText: (s: String) -> Unit)
    {
        if (initText != null)
        {
            this.onText = null
            setText(initText)
        }
        this.onText = onText
        addTextChanged
    }

    fun focus()
    {
        isFocusable = true
        isFocusableInTouchMode = true
        clearFocus()
        requestFocus()
        setSelection(text.length)
    }

    /***************************************** 文本样式 ***************************************/

    fun setBold(bold: Boolean)
    {
        typeface = if (bold) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
    }

    fun setItalic(italic: Boolean)
    {
        setTypeface(Typeface.DEFAULT, if (italic) Typeface.ITALIC else Typeface.NORMAL)
    }

    fun setTextStyle(textStyle: String)
    {
        when (textStyle)
        {
            "bold" -> paint.flags = Paint.FAKE_BOLD_TEXT_FLAG or Paint.ANTI_ALIAS_FLAG
            "delete" -> paint.flags = Paint.STRIKE_THRU_TEXT_FLAG or Paint.ANTI_ALIAS_FLAG
            "under" -> paint.flags = Paint.UNDERLINE_TEXT_FLAG or Paint.ANTI_ALIAS_FLAG
            // normal
            else -> paint.flags = Paint.ANTI_ALIAS_FLAG
        }
    }

    fun setTextSize(size: Any)
    {
        if (size is Double)
        {
            setTextSize(TypedValue.COMPLEX_UNIT_DIP, size.toFloat())
        } else
        {
            setTextSize(TypedValue.COMPLEX_UNIT_PX, size.toString().toFloat())
        }
    }

    /** 同步联动 */
    fun linkEditText(other: EditText)
    {
        var changeFlag = false
        this.addTextChangedListener()
        {
            if (changeFlag) return@addTextChangedListener
            changeFlag = true
            other.text = it
            changeFlag = false
        }
        other.addTextChangedListener()
        {
            if (changeFlag) return@addTextChangedListener
            changeFlag = true
            this.text = it
            changeFlag = false
        }
    }

    private var onClearFocusListener: ((Boolean) -> Unit)? = null

    fun setOnClearFocusListener(on: (Boolean) -> Unit)
    {
        onClearFocusListener = on
    }

//    companion object
//    {
//        val INPUT_TEXT = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
//        val INPUT_TEXT_CODE = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
//        val INPUT_DECIMAL = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
//        val INPUT_NUMBER = InputType.TYPE_CLASS_NUMBER
//        val INPUT_PASSWORD = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
//    }
}